#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <stdbool.h>
#include <math.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <pwd.h>
#include <grp.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <signal.h>//信号
#include <pthread.h>//线程
#include <arpa/inet.h>//网络
#include <sys/socket.h>
#include <netdb.h>
#include <sys/epoll.h>
#include <sys/sendfile.h>
#include <mysql/mysql.h>
//客户状态结构体
typedef struct process_stat_s{
    int flag;// 当前状态
    char curr_path[1000];//当前路径
    char local_token[300];                     //
}process_stat_t;


//检查命令行参数数量是否符合预期
#define ARGS_CHECK(argc, expected)\
    do{\
                if ((argc) != (expected)){\
                        fprintf(stderr, "args num error!\n"); \
                        exit(1); \
                }\
    }while(0)

// 检查返回值是否是错误标记,若是则打印msg和错误信息
#define ERROR_CHECK(ret, error_flag, msg) \
    do { \
         if ((ret) == (error_flag)) { \
             perror(msg); \
             exit(1); \
         } \
    } while (0)

// 将消息写入日志文件的宏函数
#define LOG_WRITE(info_num, information)\
    info_write(info_num, information);      

//以下是后续函数声明

// 定义传输协议
typedef struct transport_protocol_s{
    int flag_stat; // 命令格式与内容是否正确的标记位
    int flag_work; // 执行命令的标记位
    int command_len; // 传输内容的长度
    char buf[60]; // 传输命令的内容   
    char curr_path[60]; 
    char user_id[20];//用户id                                 
    MYSQL my_sql ;           //数据库连接
    int command;
    char token[300];
}transport_protocol_t;

//客户端cd 命令
//参数：fd_net文件描述符,filename为用户输入的目标文件
int cd(int fd_net,char *filename ,process_stat_t *ps,transport_protocol_t *tp);


// 切割加上检查用户输入命令的函数
// 参数1，客户输入的字符串
// 参数2，协议结构体指针
int check_command(char *command, transport_protocol_t *train);

// 对命令第一个单词进行检查
// 参数1，切割好的字符串
int command_judge(char *p);

// 如果后续需要有字符使用该函数检查
// 参数1，切割好的字符串
// 参数2，协议结构体指针
bool check_format(char *p, transport_protocol_t *test);

// 如果后续不应该有字符使用该函数检查 
// 参数1，切割好的字符串
bool check_add(char *p);

//建立连接，
//参数为网络socket
int connection(int *fd);

//解析命令以及执行命令
int analysis_execute(char *comment_line,int fd,process_stat_t *stat,transport_protocol_t *msg);

//登录
int login(int fd,process_stat_t *stat,transport_protocol_t *tp);

//获取文件hash值函数
//参数file_name为文件名
//传入传出参数hash_val，接收返回计算好的hash值
int getHash(const char* file_name,char *hash_val);

//客户端传输函数
//第一个参数网络socket
//第二个参数文件路径
int recvFile(int socket_fd,transport_protocol_t *msg);

//客户端接收服务端响应puts命令的调用函数
//网络socket
//要传输的文件名
int sendFile(int socket_fd,transport_protocol_t *msg);

// 用户输入mkdir时等待返回结果
// 参数1，socket文件描述符
// 参数2：协议结构体指针
int cl_mkdir(int fd);

//客户端ls函数
//参数：sockfd文件描述符，address访问的目录 
void ls(int sockfd);

//客户端rm函数
//参数：sockfd文件描述符，filename向服务端发送要被删除的文件名
void rm(int sockfd);

// 客户端打印帮助文件
// 无参数
int help(void);








// 获取当前时间的函数
// 参数1，需要放时间的字符串
int get_time(char *now_time);

// 将消息写进日志文件
// 参数1，信息等级，3为最严重，决定写入那个文件
// 参数2，写入什么信息
int info_write(int info_num, char *info);

// 获取配置文件的参数的函数
// 参数1，需要获取参数的名字
// 参数2，获取参数后放置的变量
int getparameter(char *key, char *value);

// 调用rmdir函数，接收返回结果，成功为0，失败为-1
// 参数1，文件描述符
int cli_rmdir(int fd);



//
void *func(void*arg);
